﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Hinacom.Scheduler.Manager.Views
{
    public partial class DailyScheduleView : UserControl, IScheduleView
    {
        public DailyScheduleView()
        {
            InitializeComponent();
            
            weekdayCheckboxMaps = new List<WeekdayCheckboxMap>()
            {
                new WeekdayCheckboxMap() { Box = chkMonday, Weekday = DayOfWeek.Monday },
                new WeekdayCheckboxMap() { Box = chkThursday, Weekday = DayOfWeek.Tuesday },
                new WeekdayCheckboxMap() { Box = chkWednesday, Weekday = DayOfWeek.Wednesday },
                new WeekdayCheckboxMap() { Box = chkTuesday, Weekday = DayOfWeek.Thursday },
                new WeekdayCheckboxMap() { Box = chkFriday, Weekday = DayOfWeek.Friday },
                new WeekdayCheckboxMap() { Box = chkSaturday, Weekday = DayOfWeek.Saturday },
                new WeekdayCheckboxMap() { Box = chkSunday, Weekday = DayOfWeek.Sunday }
            };
        }

        private List<WeekdayCheckboxMap> weekdayCheckboxMaps = null;
        private class WeekdayCheckboxMap
        {
            public CheckBox Box { get; set; }
            public DayOfWeek Weekday { get; set; }
        }

        void IScheduleView.ApplyJobInfo(JobInfo jobInfo)
        {
            if (!(jobInfo is DailyJobInfo))
                throw new Exception("Type mismatch. An instance of class \"Hinacom.Scheduler.DailyJobInfo\" is expected.");

            DailyJobInfo dailyJob = (DailyJobInfo)jobInfo;
            foreach (DayOfWeek weekday in dailyJob.RunOnWeekDays)
                weekdayCheckboxMaps.FirstOrDefault(m => m.Weekday == weekday).Box.Checked = true;

            dtpStartAt.Value = new DateTime(2000, 1, 1).Add(dailyJob.StartDailyAt);
            if (dailyJob.EndDailyAt.HasValue)
            {
                rdoEndAt.Checked = true;
                dtpEndAt.Value = new DateTime(2000, 1, 1).Add(dailyJob.EndDailyAt.Value);
            }
            else if (dailyJob.EndDailyAfterCount.HasValue)
            {
                rdoEndAfterCount.Checked = true;
                nmbEndCount.Value = dailyJob.EndDailyAfterCount.Value;
            }

            itvInterval.Interval = dailyJob.Interval;
        }

        JobInfo IScheduleView.CreateJobInfoInstance()
        {
            return new DailyJobInfo();
        }

        void IScheduleView.FillJobInfo(JobInfo jobInfo)
        {
            if (!(jobInfo is DailyJobInfo))
                throw new Exception("Type mismatch. An instance of class \"Hinacom.Scheduler.DailyJobInfo\" is expected.");

            DailyJobInfo dailyJob = (DailyJobInfo)jobInfo;
            dailyJob.RunOnWeekDays = weekdayCheckboxMaps.Where(m => m.Box.Checked).Select(m => m.Weekday).ToArray();

            dailyJob.StartDailyAt = dtpStartAt.Value.TimeOfDay;
            if (rdoEndAt.Checked)
                dailyJob.EndDailyAt = dtpEndAt.Value.TimeOfDay;
            else
                dailyJob.EndDailyAfterCount = Convert.ToInt32(nmbEndCount.Value);

            dailyJob.Interval = itvInterval.Interval;
        }

        bool IScheduleView.ValidateInput(StringBuilder messages)
        {
            bool valid = true;
            if (weekdayCheckboxMaps.Where(m => m.Box.Checked).ToArray().Length == 0)
            {
                valid = false;
                messages.AppendLine("Please choose the days when run the task.");
            }

            if (rdoEndAt.Checked && dtpEndAt.Value.TimeOfDay < dtpStartAt.Value.TimeOfDay)
            {
                valid = false;
                messages.AppendLine("The end time shouldn't be eralier than start time.");
            }

            bool runonce = rdoEndAfterCount.Checked && nmbEndCount.Value == 1;
            if (!runonce && itvInterval.Interval.Ticks == 0)
            {
                valid = false;
                messages.AppendLine("Please specify the repeat interval.");
            }

            return valid;
        }

        private void RefreshRadioButtonStatus()
        {
            dtpEndAt.Enabled = rdoEndAt.Checked;
            nmbEndCount.Enabled = rdoEndAfterCount.Checked;
        }

        private void BatchProcessWeekdayCheckbox(Func<WeekdayCheckboxMap, bool> predict, bool check)
        {
            List<WeekdayCheckboxMap> maps = weekdayCheckboxMaps;
            if (predict != null)
                maps = maps.Where(predict).ToList();
            maps.ForEach(x => { x.Box.Checked = check; });
        }

        #region Events
        private void lnkAllDays_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BatchProcessWeekdayCheckbox(null, true);
        }

        private void lnkWorkingDays_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BatchProcessWeekdayCheckbox(m => m.Weekday > DayOfWeek.Sunday && m.Weekday < DayOfWeek.Saturday, true);
        }

        private void lnkWeekend_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BatchProcessWeekdayCheckbox(m => m.Weekday == DayOfWeek.Sunday || m.Weekday == DayOfWeek.Saturday, true);
        }

        private void lnkClearAll_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BatchProcessWeekdayCheckbox(null, false);
        }

        private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            RefreshRadioButtonStatus();
        }
        #endregion
    }
}
